<!DOCTYPE html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>KataGo</title>
    <link rel="stylesheet" href="index.css">
    <script type="text/javascript" src="sw.js"></script>
  </head>
  <body>
    <div id="root">
      <div class="controls">
        <div>
          <select id="links">
            <option value="none" selected>KataGo</option>
            <option value="https://github.com/lightvector/KataGo">GitHub</option>
            <option value="https://katagotraining.org/">training</option>
            <option value="https://github.com/lightvector/KataGo/blob/master/docs/GTP_Extensions.md">GTP</option>
          </select>
        </div>
        <div>
          <select id="subcommand">
            <option value="gtp">gtp</option>
            <!-- <option value="analysis">analysis</option> -->
          </select>
        </div>
        <div>
          <span>model</span>
          <select id="model">
            <option value="b6c96-s175395328-d26788732">b6c96-s175395328-d26788732</option>
          </select>
        </div>
      </div>
      <div class="controls">
        <div>
          <span>config</span>
          <select id="configFile">
            <option value="none">default</option>
            <option value="gtp_auto.cfg">gtp_auto.cfg</option>
          </select>
        </div>

        <div>
          <span>bordsize</span>
          <select id="boardsize">
            <option value="19">19</option>
            <option value="13">13</option>
            <option value="9">9</option>
          </select>
        </div>
        <div>
          <span>backend</span>
          <select id="backend">
            <option value="auto">auto</option>
            <option value="webgl">webgl</option>
            <option value="wasm">wasm</option>
            <!-- <option value="cpu">cpu</option> -->
          </select>
        </div>
        <div>
          <span>maxTime</span>
          <select id="maxTime">
            <option value="none">none</option>
            <option value="1">1</option>
            <option value="3">3</option>
            <option value="5">5</option>
            <option value="10">10</option>
          </select>
        </div>
      </div>

      <textarea id="output" cols="30" rows="10" placeholder="GTP output" disabled></textarea>

      <div class="controls">
        <div>
          <span>play</span>
          <input type="text" id="play">
          <button id="playBlack">B</button>
          <button id="playWhite">W</button>
        </div>
        <div>
          <span>genmove</span>
          <button id="genmoveBlack">B</button>
          <button id="genmoveWhite">W</button>
          <input type="checkbox" id="analyze" name="analyze" checked>
          <label for="analyze">analyze</label>
        </div>
        <div>
          <button id="showboard">showboard</button>
          <input type="checkbox" id="showboardAuto" name="showboardAuto" checked>
          <label for="showboardAuto">auto</label>
        </div>
        <div>
          <span>kata-analyze</span>
          <button id="kata-analyze">start</button>
        </div>
        <div>
          <span>loadsgf</span>
          <select id="loadsgf">
            <option value="none">none</option>
            <option value="15820101-HSansa-KRigen.sgf">15820101-HSansa-KRigen.sgf</option>
            <option value="20160309-LSedol-AlphaGo.sgf">20160309-LSedol-AlphaGo.sgf</option>
          </select>
        </div>
      </div>
      <form id="input">
        <input type="text" id="command" name="command" placeholder="starting KataGo..." disabled>
      </form>
    </div>

    <script type="text/javascript" src="katago.js"></script>
    <script type="text/javascript">
      const urlParams = new URL(document.location).searchParams;

      const linksSelect = document.getElementById("links");
      const subcommandSelect = document.getElementById("subcommand");
      const configFileSelect = document.getElementById("configFile");
      const modelSelect = document.getElementById("model");
      const boardsizeSelect = document.getElementById("boardsize");
      const backendSelect = document.getElementById("backend");
      const maxTimeSelect = document.getElementById("maxTime");

      const inputForm = document.getElementById("input");
      const cmdInput = document.getElementById("command");
      const outputTextarea = document.getElementById("output");

      const showboardButton = document.getElementById("showboard");
      const showboardCheckbox = document.getElementById("showboardAuto");
      const playInput = document.getElementById("play");
      const playBlackButton = document.getElementById("playBlack");
      const playWhiteButton = document.getElementById("playWhite");
      const genmoveBlackButton = document.getElementById("genmoveBlack");
      const genmoveWhiteButton = document.getElementById("genmoveWhite");
      const analyzeCheckbox = document.getElementById("analyze");
      const loadsgfSelect = document.getElementById("loadsgf");
      const kataAnalyzeButton = document.getElementById("kata-analyze");

      var dispatchMessage;
      var loadsgf;

      function dispatchCommand(cmdStr) {
        const cmdLine = cmdStr + "\n";
        console.log("[UI] dispatch cmd:", cmdStr);
        outputTextarea.value += cmdLine;
        outputTextarea.scrollTop = outputTextarea.scrollHeight;

        // allow time for textarea to update before blocking UI
        setTimeout(_ => dispatchMessage(cmdLine), 100);
      }

      function genmove(color) {
        dispatchCommand((analyzeCheckbox.checked ? "genmove_analyze" : "genmove") + " " + color);
        if (showboardCheckbox.checked) dispatchCommand("showboard");
      }

      function play(color) {
        dispatchCommand("play " + color + " " + playInput.value);
        if (showboardCheckbox.checked) dispatchCommand("showboard");
        playInput.value = "";
      }

      function initSelect(selectElem, urlParam, defaultValue) {
        let value = urlParams.get(urlParam) || defaultValue;
        selectElem.value = value;
        selectElem.onchange = ev => {
          let url = new URL(document.location.href);
          url.searchParams.set(urlParam, selectElem.value);
          document.location.href = url.href;
        };
        return value == "none" ? null : value;
      }

      linksSelect.onchange = ev => {
        window.open(linksSelect.value);
        linksSelect.value = "none";
      };

      let subcommandValue = initSelect(subcommandSelect, "subcommand", "gtp");
      let configFileValue = initSelect(configFileSelect, "configFile", "none");
      let modelValue = initSelect(modelSelect, "model", "b6c96-s175395328-d26788732");
      let boardsizeValue = initSelect(boardsizeSelect, "boardsize", "19");
      let backendValue = initSelect(backendSelect, "backend", "auto");
      let maxTimeValue = initSelect(maxTimeSelect, "maxTime", "none");

      showboardButton.onclick = _ => dispatchCommand("showboard");
      playBlackButton.onclick = _ => play("black");
      playWhiteButton.onclick = _ => play("white");
      genmoveBlackButton.onclick = _ => genmove("black");
      genmoveWhiteButton.onclick = _ => genmove("white");
      loadsgfSelect.onchange = _ => loadsgf(loadsgfSelect.value);
      kataAnalyzeButton.onclick = _ => {
        switch (kataAnalyzeButton.textContent) {
          case "start": kataAnalyzeButton.textContent = "stop"; dispatchCommand("kata-analyze black 100"); break;
          case "stop":  kataAnalyzeButton.textContent = "start"; dispatchCommand("stop"); break;
        }
      }


      inputForm.onsubmit = ev => {
        ev.preventDefault();
        dispatchCommand(cmdInput.value);
        cmdInput.value = "";
      };

      function onKatagoStatus(status) {
        switch (status) {
          case 1: // ready
            cmdInput.removeAttribute("disabled");
            cmdInput.setAttribute("placeholder", "GTP command");
            cmdInput.focus();
            break;

          case -1: // fail
            cmdInput.setAttribute("placeholder", "Engine failed loading a weight");
        }
      }

      function onKatagoMessage(msgStr) {
        outputTextarea.value += msgStr + "\n";
        outputTextarea.scrollTop = outputTextarea.scrollHeight;
      }

      const katagoParams = {
        subcommand: subcommandValue,

        configFile: configFileValue,
        config: {
          tfjsBackend: backendValue,
          defaultBoardSize: boardsizeValue,

          // maxTime: 3,
          maxVisits: 25, // limits size of search tree
          // maxPlayouts: 300, // limits new searches per move
        },

        model: "web_models/" + modelValue + "_" + boardsizeValue,
      };

      if (!crossOriginIsolated) {

        outputTextarea.value += "ERROR: no cross-origin isolation\n";

      } else {

        let kataGoInstance;

        dispatchMessage = msg => kataGoInstance.postCommand(msg);
        loadsgf = sgfFile => {
          if (sgfFile == "none")
            dispatchCommand("clear_board");
          else
            fetch("sgf_files/" + sgfFile).then(res => res.text())
            .then(sgfText => {
              kataGoInstance.FS.writeFile(sgfFile, sgfText);
              dispatchCommand("loadsgf " + sgfFile);
              dispatchCommand("showboard");
            });
        }

        outputTextarea.value += "loading KataGo in UI thread...\n";

        // katagoParams["preRun"] = [
        //   ({FS}) => FS.writeFile("sample.sgf", "(;B[ee];W[cc])");
        // ];
        katagoParams["onstatus"] = onKatagoStatus;
        katagoParams["onmessage"] = onKatagoMessage;

        KataGo(katagoParams).then(kg => {
          kataGoInstance = kg;
          console.log("KataGo ready", kg);
        });
      }
    </script>
  </body>
</html>
